CHARMODE DEMO
                An Amiga Character mapped display mode generated by Custom Chips

FEATURES        Same-field update of the entire screen with beam avoidance
                Support for up to 640 x 287 resolution (currently PAL only)
                font support for up to 256 characters each up to 16 pixels tall
                Support for dynamic font changes from one field to the next

Remaps screens encoded as one byte per character into Amiga bitplane graphics.

This demo uses the copper to generate a custom screen mode and convert 
character codes into graphic patterns from a font, by programming the blitter. 
All processing is performed by the custom chips. All the CPU need do is write a 
small table of character codes to determine the new display. Almost all the 
main CPU time is available for other purposes.

This document is edited from the 'internal' development documentation, and 
should be read in conjunction with the fuller explanations in Amiga Format.

CharMode is intended for use in emulators for vintage computers and terminals  
with character-mapped displays. These include TRS-80 (64 x 16 characters of 8 x 
12 pixels, on a 512 x 192 pixel grid), CP/M, IBM MDA and most ASCII terminals 
(typically 80 x 24 or 80 x 25 characters), PET (40x25 8 x 8 characters), ZX80 
and ZX81 (32 x 24 characters), MSX, Dragon, Atari, etc.

It uses a font of 256 characters, each eight pixels wide and up to 16 pixels 
tall, with one byte, left justified, in each pattern WORD. Thus the font takes 
256 (characters) x 32 (bytes) = 8K. If  the character height is less than 16 
pixels the rendered character is truncated at the bottom.

Dynamic font changes are supported on a per-field basis by writing the changed 
data to the corresponding font words. These need to be unpacked as the font 
must use one WORD per character line (as it's a 16 bit blitter). Automatic 
unpacking of 8 x 8 fonts is implemented.

Supported Screen formats:

  Char Width Char Height Chars/Row  Chars/Col     Prime Time  Characters

        8               8               80              24              58              1920
        8               8               80              25              47              2000    
        8               8               80              28              17              2240            
        8               8               80              29              6               2320
        8               10              80              24              14              1920
        8               12              80              20              20              1600
        8               16              80              16              8               1280
        
        8               8               64              32              40              2048
        8               8               64              35              15              2240

        8               16              64              16              40              1024
        8               12              64              16              52              1024
        8               10              64              25              52              1600

Those formats are high resolution. Thsse are some low resolution formats:

        8               8               40              24              106             960
        8               8               40              25              97              1000
        8               8               40              32              40              1280
        8               10              40              24              62              960
        8               10              40              25              52              1000
        8               12              40              16              108             640             
        8               16              40              16              40              640

        8               8               32              24              106             768
        8               8               32              32              40              1024
        8               10              32              24              62              768
        8               12              32              20              60              640     
        8               16              32              16              40              512

These are all tested examples. Many other formats are possible; in general the 
code expects widths of 32, 40, 64 or 80 characters and from 16 to 32 lines. 
Other values may require additional ad hoc code to fine-tune display timing.

Notes on the formats

Char Heights are in Pixels. All character widths are eight pixels. Line widths 
must be even as we're using a 16 bit chip set. Prime Time is the number of scan 
lines of time available from the start of the field before the copper starts to 
blit character patterns. Normally this is padded by adding HeadLines - scan 
lines when the display is visible but not part of the blitted character map. 25 
undisplayed scans are available at the start of each field. In practice one 
additional line time should be allowed for the copper initialisation at the 
start of each field.

It's advantageous to allow more lines, but this moves the character mapped 
screen portion down the display. With 2000 8 x 8 pixel characters on-screen (25 
lines of 80 columns) up to 87 lines of heading are supported (in PAL mode the 
line limit is 287, and 25 x 8 = 200 pixels for the character map) and this 
gives the latest allowable character map on the screen, with the maximum time 
for updates at the start of the field - around 5500 microseconds.

High values of Prime Time indicate that the display could be moved higher up 
the screen (rather than extending to display line 287) while still allowing 
VBLANK updates. If the Prime Time value is low it may be necessary to start the 
CPU update as the blitter finishes updating the last character and the last 
line begins to be displayed - this boosts the available time from a 
near-impossible eight lines to 24 with 80 x 16 8 x 16 characters.

Beam Avoidance is assured by timing the blits so that the last blit for the 
last line is complete before that row of characters starts to be displayed. It 
follows that character map or font updates can be performed at any time from 
the start of display of that line, rather than top of frame. This is more 
complicated than waiting for VBLANK - it requires a copper interrupt - but 
gives more time for interrupt response and update before the data is needed for 
the next field.

These modes are expected to be used on machines with fast memory, as much of 
the chip RAM bus bandwidth is consumed by the copper and blitter updates. It 
makes sense to keep the master copy of the current screen in fast RAM. If the 
fast memory is more than twice the speed of chip RAM - as in the case of A3000 
and A4000 systems, and expanded machines with processor-local 32 bit memory on 
the CPU card - it is generally worth keeping a second copy of the last screen 
written in fast RAM, and only writing changed information at the start of a 
field. A similar technique can be used for font updates, as it's rare that the 
entire font will change every field.

Word or long word transfers are important to ensure quick enough updates from 
fast RAM to chip RAM. It may be worth adding a blitter pass to expand the font 
from byte to word format. The trade-off is the extra chip bandwidth required 
against the reduced time that the CPU spends waiting for writes to Chip RAM to 
be completed.

HiRes character updates are performed with the BLITTER_NASTY bit set, consuming 
all available processor memory cycles as each character is generated, but the 
processor still gains access to memory at least four times per scan line as 
WAITs are interspersed between the blits. There's much more bandwidth available 
just before and after the vertical blank, and that is when writes to the font 
and character map should be performed. Not only does the processor get more 
time then, it's the ideal point at which to copy the emulated screen to the 
real screen hardware to minimise delay and ensure field synchronisation, with 
all characters changed in a given emulated field guaranteed to appear in the 
next display.

The blitter and copper instructions used are compatible with all Amigas from 
the original OCS through ECS to AGA. 30 KHz VGA monitor support could be but is 
not included. Scan doubling would require lines to be generated twice as 
quickly.

The current code is designed for a 15 KHz PAL display and would need changes 
for other modes. It was developed and tested with Amiga Qdos, and is intended 
to be used in custom screens on the Amiga, with ownership of the blitter 
throughout updates, only relinquishing it when the emulator screen is swapped 
off or paused.

The code sets out to centre the display vertically and horizontally, while 
ensuring plenty of free time at the start of each field for updates from the 
CPU. In total, the display must be at least 192 pixels tall and start by scan 
64 - well within limits of all Amiga chip sets.

Extra lines can be added at the top of the display. These are not used for the 
character map but can be written (albeit slowly) by the processor and are ideal 
for headings, menus and emulator status. They are added at the top to give the 
blitter more time to generate the field without beam splitting. In order to 
leave some bandwidth for the CPU, even in the middle of the bitmap, high 
resolution 8 x 8 pixel character blits need slightly more blitter and copper 
DMA time than they take to be output, so generation must start earlier.

For instance a display of the maximum number of characters (2320, in 80 columns 
and 29 rows) requires at least 50 display scan lines of head-start to ensure 
that all character lines are regenerated ahead of the beam. This comes close to 
the limit of 29 x 8 = 232 pixel lines of text and 55 for the HeadLines. No more 
than 30 line times are available at the start of the field for CPU screen 
updates - less than 2 milliseconds.

That is not long, even when there's only about two and a quarter K that needs 
to be written to update the entire screen. Allow for interrupt latency (up to 4 
lines) & remember that Chip RAM bandwidth available to the CPU may be as low as 
1.8 Mb per second on many Amigas, even without DMA contention, so that a full 
screen character write can take up to 20 scan lines to be completed! At best, 
on Commodore 68030 or Phase Five accelerators, 5 lines are needed.

As of version 0.13, the code was not optimised to work out the best wait 
between blits and ideal start line for LowRes characters, or HiRes characters 
more than 12 pixels high. It may finish blitting long before the last line, 
indicating that more time could be available between blits or (possibly) they 
could all start later. The ad-hoc code to work out Prime Time only attempts to 
maximise it for less tall characters, where the copper overhead for each blit 
is more significant and keeping up with the beam is problematic.


COPPER LIST COMPILER

The Copper list is generated by a SuperBASIC program, the Copper List Compiler. 
This contains instructions to do the following things 50 times per second:

(1) Set up a custom bitplane display centred on the PAL screen
(2) Expand an 8 x 8 pixel character font into internal format for blitting
(3) Convert an 8 bit table of character codes into pattern blit instructions
(4) Generate the new display by blitting one pattern for each character code

The Copper list Compiler (CharMode_bas) also calculates and displays the number 
of the line on which blitting will start, so that the user can ensure CPU 
updates will occur in time. Extra lines can be allocated to ensure beam 
avoidance. It can include instructions to show the time taken for each activity 
by colour-coding the screen in stripes.

The Compiler has been tested on systems ranging from AGA A4000/060 to ECS A500. 
All supporting software is PD. It uses SuperBASIC extensions, all of which are 
provided with the exception of Toolkit 2 or PD Toolkit. The BOOT program 
assumes that Toolkit 2 is available.

Compilation parameters

To generate a custom copper list for a given display format, change the 
assignment of these variables at the start of AutoChar_bas.

ShowTime        0 or 1  Flag - set to get coloured stripes on screen

Green: extracting even characters from the character map to the Copper List.

Blue: extracting even characters from the character map to the Copper List.

Red: ascending pass blitter unpack. CPU update can overlap if working forwards

Purple: descending pass of blitter unpack - changes in this phase get displayed
        one field late - but blitter is not BUSY so CPU writes go at reasonable
        speed.

Dark Blue: rendering characters by blitting patterns from the font. This area
        should end before the start of display of the last character line.

Blitfont 0 or 1 Flag - expand 8 x 8 font to 8 x 16 automatically every field?

This is too slow to be feasible with a full screen HighRes display, but can be 
performed on a partial-height screen if HeadLines are allocated to give time 
for the update at the start of each field. It only works with an 8 x 8 
character font.

BlitChars       0 or 1  Flag - include code to expand the CharMap?

        Otherwise to change a character you need to poke a word giving the base 
address of its pattern in the font into the copper list at a corresponding 
position. For instance with an 8 pixel tall font, to display character 65 
(ASCII "A") you'd poke 65 x16 (bytes per character) into the copper list. 
Multiply by 32 for characters up to 16 pixels tall.

The characters are controlled by words between the pointers FirstCharMove and
LastCharMove (both absolute addresses). The first character's font pointer 
word is at FirstCharMove. The second is FOUR BYTES EARLIER. The third is 20 
bytes on from the first, the fourth is at offset 16 from the start, and so on:

FirstCharMove,FirstCharMove-4, 20, 16, 40, 36, ... LastCharMove+4,LastCharMove

CharHeight%     1 to 16 Height of each character in pixels

        Typically 8, 9, 10, 12 or 16. fonts 8, 9 and 16 pixels high are
        included. The tallest uses IBM PC character codes, the shortest follows
        the MGT SAM convention with duplicates of the ASCII set 32-127 in the
        second half (ignoring bit 7) while the nine pixel high one is the 256
        character Minerva Qdos set.

CharWidth%      8               THIS CANNOT BE CHANGED!

CharColumns%    32,40,64,80     Number of characters on each display line

        High Resolution (70 nS pixel) mode is used for widths over 40
        characters (320 pixels)
        Other even values also work but may not be optimally timed. 
        Odd values are not allowed, for reasons of 16 bit alignment.


CharLines% 1 to 35      Number of character lines

HeadLines% 0 to 279 Number of pixel lines in bitplane BEFORE characters start

These is an interaction between these two. When a large number of CharLines% is 
chosen, the blitter needs more time to render them, so HeadLines% may be 
required to delay the display of characters until the blitter has had time to 
render them. This has the unfortunate effect of pushing the display down the 
screen, but does give some extra space for menus or headings at the top.

There's no reason why the HeadLines should not be in a different mode, although 
the compiler assumes one bit map for the characters and heading. The important 
thing is to delay output of the characters to give time for CPU update of the 
CharMap and font, Copper and Blitter unpacking of those into more Copper and 
Blitter data, and ensure that rendering of the characters still precedes the 
beam!

The compiled Copper list uses absolute addresses but can be relocated to any 
64K boundary by adjusting the pointers to PAGE, set at or fairly near the 
start. The page alignment is vital because the font must be at the start of a 
page so that it can be efficiently indexed with scaled character codes from 
zero in the low word of blitter pointers.

Compiler Limitations

This section discusses the limits imposed by the choice of data structures and 
design of the Copper List Compiler. These are practical limits associated with 
the current implementation on  OCS Amiga hardware, rather than theoretical 
limits of the CharMode principle.

The current version of the compiler (0.13) only supports dynamic font 
unpacking for 8 x 8 character fonts. This suits all the machines (Atari, C64, 
MSX, Sinclair ZX-81) which require it. Taller fonts are supported but not 
dynamic. In other words modified bytes must be written unpacked (16 bits wide, 
left justified). The unpacking consumes quite a lot of blitter time - too much 
for full-screen HiRes display. It's fine for displays of up to about 1000 
characters, and again that corresponds to the displays we'd want to emulate.

The compiler assumes a 50 Hertz PAL display with up to 287 lines. NTSC and 
Double-scan VGA modes could be supported but with reduced performance as the 
display pushes out more pixels for a given amount of time available for blitter 
activity.

Characters must be eight pixels wide. This is a consequence of the way the 
blitter is used to render two characters at once. Peter Corlett had this key 
idea, without which the code would be much slower as it would need to mask and 
generate one character at a time. It's easy to render 16-pixel wide characters 
at fair speed with simple un-masked blits, but in general other widths would be 
rendered much more slowly.

These modes all use a single bitplane and two colours. This minimise Amiga Chip 
RAM and bandwidth requirements, and suits the old monochrome screens which were 
standard for character-mapped modes.

Colour character-mapped modes could supported analogously but need a different 
approach as all output goes to a single bitplane. This can be re-coloured 
efficiently with a copper list, but the extra copper instructions to change 
colours must be fitted around the existing heavy copper activity. Attribute 
plus bitplane graphics (as on C64, MSX, SAM, Spectrum and TI-99/4) can be 
emulated similarly, although the heavy copper-blitting characteristic of 
character-mapped emulation is not needed in such cases.

                        Simon N Goodwin, simon@studio.woden.com, January 2000

DATA STRUCTURES

The CharMode data structures start on a 64K boundary in Chip memory. font and 
Bitplane data is guaranteed to fit in the first 64K, while the Copper list will 
start there but may extend into the next 64K page.

font                   size:   8K (allocated - may not be all used)

If  LoRes 8 x 8 characters are in use the font is stored in two forms. At 
offset +4096 there is a 2K packed byte image, as would be used in an 8 bit 
micro, with 8 x 256 bytes per character. This is immediately preceded by a 
blitter-generated 4K version, identical but that each packed byte is followed 
by a zero byte for convenience when performing 16 bit blits. The packed data is 
followed by 2K of unused space. To change the font, the CPU simply writes the 
changes into the packed area and they are unpacked and used automatically by 
the copper and blitter.

If HiRes characters are in use or the character height is not eight, the font 
is only stored in unpacked form with 16 by 16 bits per character. Again valid 
pixel data is only in the eight most significant bits of each word, but each 
character supports up to 16 words. If the font needs to be changed on the fly 
the CPU must store new data bytes at unpacked word intervals, as unpacking is 
only automatic for LowRes 8 x 8 characters.

For ease of addressing the number of rows in each character should be a power 
of two even if the number of rows used is not - e.g. 16 for 10, 12 or 16 pixel 
tall characters, and eight for characters up to 8 pixels tall.

The order of characters corresponds to the character code from 0 to 255, and 
need not be standard ASCII - it could be a variant like PET or TRS-80 ASCII or 
something entirely different, such as ZX-80 or ZX-81 character codes. You can 
switch between two fonts at the same Chip address MOD 65536 with just two 
POKEs to the copper list, setting BLTAPT.H and BPLBPT.H to point to the 
required page.

Bitplane sizes: 12K for 64x16 characters of 8x12 pixels each (HiRes 512 x 192)
               8000 bytes for 40 x 25 8 x 8 pixel characters (LoRes 320 x 200)

A conventional Amiga bit map with one word for 16 pixels and lines consecutive 
in memory. Allow for HeadLines and border pixels, if any, adding to the size of 
the bitplane. There is a gap of 128 bytes at the end of the bitplane before the 
font data starts.

Character Map   size:   1K to 2K typically.

One byte for each character to be displayed, as a linear array with no gaps 
between lines, e.g. the data for the second line of a 32 column x 16 line 
screen starts with the 33rd byte. These bytes are shifted by four or five 
places and inserted into the Copper List. In modes with no more than 1024 
characters this is automatically unpacked into the Copper list before each new 
field is displayed.

Copper List: A few hundred bytes of overhead + 20 bytes per character to blit

This is the clever bit. It contains anything up to 45K of Copper instructions 
which must be executed every field (i.e. 50 times per second). These start by 
setting up the display, but most of their effort goes into programming the 
blitter to read the font for each byte in the character map and copy it to the 
correct place in the Bit Map. Optional coloured stripes can show the time when 
the copper is busiest and confirm beam avoidance without double buffering.

If  automatic font expansion is in use then the blitter unpacks the 8 x 8 
pixel font patterns into 8 x 16 bit words before it starts to blit characters. 
Unpacking is performed in two passes, ascending and descending. The blitter 
avoids hogging the bus (not 'nasty') so the CPU can finish off font writes 
without falling behind the beam, at least during the ascending pass. If it's 
still writing during the descending pass, those updates will not appear in the 
unpacked font till the next field.

The blitter is switched into 'nasty' mode for the individual HiRes character 
blits, which are short and well spaced so the CPU can get through between them 
- although it will have to wait much more than if it got its writes done 
earlier in the field. In general, the earlier the better.
